package com.zkh.myutils.proxy.util;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.zkh.myutils.utils.Assert;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;

/**
 * 类型属性
 * @author zkh
 */
public class TypeBean {
	//基础类型
	private static List<String> baseTypes = Arrays.asList("Z", "C", "B", "S", "I", "F", "J", "D");
	//基础类型转换映射
	private static Map<String, BaseTypeCastBean> baseTypeCastMap = BaseTypeCastBean.getBaseTypeCastMap(
		new BaseTypeCastBean("F", "java/lang/Float", "floatValue", "()F", Opcodes.FRETURN),
		new BaseTypeCastBean("J", "java/lang/Long", "longValue", "()J", Opcodes.LRETURN),
		new BaseTypeCastBean("D", "java/lang/Double", "doubleValue", "()D", Opcodes.DRETURN),
		new BaseTypeCastBean("Z", "java/lang/Boolean", "booleanValue", "()Z", Opcodes.IRETURN),
		new BaseTypeCastBean("B", "java/lang/Byte", "byteValue", "()B", Opcodes.IRETURN),
		new BaseTypeCastBean("S", "java/lang/Short", "shortValue", "()S", Opcodes.IRETURN),
		new BaseTypeCastBean("I", "java/lang/Integer", "intValue", "()I", Opcodes.IRETURN),
		new BaseTypeCastBean("C", "java/lang/Character", "charValue", "()C", Opcodes.IRETURN)
	);
	//基础类型对应的包装类型
	private static Map<String, String> baseWrapMap = new HashMap<>();
	//类型
	private Type type;
	//长度（double和long占两帧，其它占一帧）
	private int length;
	//描述符
	private String descriptor;
	//类型
	private String className;
	//指定特殊类型
	private String special;

	public TypeBean(Type type, int length, String descriptor, String className) {
		super();
		this.type = type;
		this.length = length;
		this.descriptor = descriptor;
		this.className = className;
		//特殊类型转换
		this.special = Assert.getIfElse(descriptor.startsWith("["), descriptor, className.replace('.', '/'));
	}
	
	//处理基础类型和包装类型的映射
	static {
		baseWrapMap.put("Z", "java/lang/Boolean");
		baseWrapMap.put("C", "java/lang/Character");
		baseWrapMap.put("B", "java/lang/Byte");
		baseWrapMap.put("S", "java/lang/Short");
		baseWrapMap.put("I", "java/lang/Integer");
		baseWrapMap.put("F", "java/lang/Float");
		baseWrapMap.put("J", "java/lang/Long");
		baseWrapMap.put("D", "java/lang/Double");
	}
	
	/**
	 * 是否为原始类型或其数组
	 */
	public boolean isOriginType() {
		return baseTypes.contains(descriptor);
	}
	
	/**
	 * 获取加载类型
	 */
	public int getLoadType() {
		switch(descriptor) {
			case "F":
				return Opcodes.FLOAD;
			case "J":
				return Opcodes.LLOAD;
			case "D":
				return Opcodes.DLOAD;
			default:
				return Opcodes.ILOAD;
		}
	}
	
	/**
	 * 获取返回类型
	 */
	public int getReturnType(MethodVisitor mv) {
		switch(descriptor) {
			case "F":
				Assert.doIfNotNull(mv, v->v.visitInsn(Opcodes.FCONST_0));
				return Opcodes.FRETURN;
			case "J":
				Assert.doIfNotNull(mv, v->v.visitInsn(Opcodes.LCONST_0));
				return Opcodes.LRETURN;
			case "D":
				Assert.doIfNotNull(mv, v->v.visitInsn(Opcodes.DCONST_0));
				return Opcodes.DRETURN;
			case "Z":
			case "B":
			case "S":
			case "I":
				Assert.doIfNotNull(mv, v->v.visitInsn(Opcodes.ICONST_0));
				return Opcodes.IRETURN;
			case "C":
				Assert.doIfNotNull(mv, v->v.visitLdcInsn(new Integer(' ')));
				return Opcodes.IRETURN;
			case "V":
				return Opcodes.RETURN;
			default:
				Assert.doIfNotNull(mv, v->mv.visitInsn(Opcodes.ACONST_NULL));
				return Opcodes.ARETURN;
		}
	}
	/**
	 * 获取返回类型
	 */
	public int getReturnTypeCast(MethodVisitor mv) {
		//检查是否是数组
		if(descriptor.startsWith("[")) {
			//检查类型转换
			mv.visitTypeInsn(Opcodes.CHECKCAST, descriptor);
			mv.visitTypeInsn(Opcodes.CHECKCAST, descriptor);
			//返回对象类型
			return Opcodes.ARETURN;
		}
		//不是数组
		else {
			//获取基础类型
			BaseTypeCastBean bean = baseTypeCastMap.get(descriptor);
			//如果是基础类型
			if(bean!=null) {
				mv.visitTypeInsn(Opcodes.CHECKCAST, bean.getTypeName());
		        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bean.getTypeName(), bean.getTransMethod(), bean.getReturnDesc(), false);
		        //返回类型
		        return bean.getReturnType();
			}
			//无返回值
			else if("V".equals(descriptor)) {
				return Opcodes.RETURN;
			}
			//其它类型的值
			else {
				mv.visitTypeInsn(Opcodes.CHECKCAST, special);
				return Opcodes.ARETURN;
			}
		}
	}
	
	/**
	 * 获取值
	 */
	public Integer getArrType() {
		switch(descriptor) {
			case "F":
				return Opcodes.FLOAT;
			case "J":
				return Opcodes.LONG;
			case "D":
				return Opcodes.DOUBLE;
			default:
				return Opcodes.INTEGER;
		}
	}
	
	/**
	 * 获取方法描述
	 */
	public String[] getMethodDesc() {
		//包装类
		String wrapType = baseWrapMap.get(descriptor);
		//返回
		return new String[] {wrapType, "(" + descriptor + ")L" + wrapType + ";"};
	}
	
	public Type getType() {
		return type;
	}
	public void setType(Type type) {
		this.type = type;
	}
	public int getLength() {
		return length;
	}
	public void setLength(int length) {
		this.length = length;
	}
	public String getDescriptor() {
		return descriptor;
	}
	public void setDescriptor(String descriptor) {
		this.descriptor = descriptor;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getWrapType() {
		return baseWrapMap.get(descriptor);
	}
	public String getSpecial() {
		return special;
	}

	@Override
	public String toString() {
		return "TypeBean [type=" + type + ", length=" + length + ", descriptor="
				+ descriptor + ", className=" + className + ", special="
				+ special + "]";
	}
}
